package cn.com.rexen.rplus.controller;

import cn.com.rexen.rplus.core.criteria.Page;
import cn.com.rexen.rplus.core.service.IService;
import cn.com.rexen.rplus.sa.model.BaseVO;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.List;

/**
 * 增删改查基础Controller.
 *
 * @param <T> 泛型支持.
 * @version 1.0.0
 */
public abstract class AbstractCURDControllerSupport<T extends Serializable, V extends BaseVO> extends ControllerSupport {

    /**
     * 抽象的实体对象.
     *
     * @return Object.
     */
    public abstract T getEntity();

    /**
     * 获取实体服务类的实例(返回Service一个接口).
     *
     * @return IService.
     */
    protected abstract IService getEntityService();


    /**
     * list查询方法的实现(目前没有做成通用的，由子类方法实现).
     *
     * @param request  http请求.
     * @param response http响应.
     * @return Page 分页信息.
     */
    protected abstract Page doList(HttpServletRequest request, HttpServletResponse response);

    /**
     * 查询实体信息(show.do)回调函数，在返回视图之前调用用。可以继续添加返回信息.
     *
     * @param request  http请求.
     * @param response http响应.
     * @param id   实体对象主键ID
     * @param modelMap ModelMap.
     * @return VO对象.
     */
    protected abstract T doShow(HttpServletRequest request, HttpServletResponse response, Serializable id, ModelMap modelMap);


    /**
     * 分页查询(list.do)回调函数，该方法在执行查询之前调用。可以继续添加过滤条件和排序条件.
     *
     * @param request  http请求.
     * @param response http响应.
     */
    protected void beforeList(HttpServletRequest request, HttpServletResponse response) {
    }

    /**
     * 分页查询(list.do)回调函数，该方法在返回视图之前调用。可以继续添加返回信息.
     *
     * @param request  http请求.
     * @param response http响应.
     * @param mm       ModelMap .
     * @param page     分页信息.
     */
    protected void afterList(HttpServletRequest request, HttpServletResponse response, ModelMap mm, Page page) {
    }


    /**
     * 保存实体回调函数，在执行实体与Request参数绑定之前调用用。 注意：由于entity可能是托管对象，对entity所做的修改都将反映到数据库。
     * 所以有必要在此方法中进行前期的数据校验，以免发生意外.
     *
     * @param request http请求.
     * @param entity  VO对象.
     * @param mm      modelmap.
     * @return 是否通过校验
     */
    protected boolean beforeBindSaveRequestEntity(HttpServletRequest request, HttpServletResponse response, T entity, ModelMap mm) {
        return false;
    }

    /**
     * 修改实体回调函数，在执行实体与Request参数绑定之前调用用。 注意：由于entity可能是托管对象，对entity所做的修改都将反映到数据库。
     * 所以有必要在此方法中进行前期的数据校验，以免发生意外.
     *
     * @param request http请求.
     * @param entity  VO对象.
     * @param mm      modelmap.
     * @return 是否通过校验
     */
    protected boolean beforeBindUpdateRequestEntity(HttpServletRequest request, HttpServletResponse response, T entity, ModelMap mm) {
        return false;
    }

    /**
     * 保存实体(save)回调函数，在执行保存之前调用用。可以进行数据校验.
     *
     * @param request HttpServletRequest
     * @param entity  实体对象
     * @param errors  BindException 可以添加错误信息
     * @param mm      ModelAndView
     */
    protected void beforeSave(HttpServletRequest request, HttpServletResponse response, V entity, BindException errors, ModelMap mm) {
    }

    /**
     * 保存实体(save)回调函数，在返回视图之前调用用。可以继续添加返回信息.
     *
     * @param request  http请求.
     * @param response http响应.
     * @param mm       ModelMap.
     * @param entity   VO对象.
     */
    protected void afterSave(HttpServletRequest request, HttpServletResponse response, ModelMap mm, V entity) {
    }

    /**
     * 保存实体(update)回调函数，在执行保存之前调用用。可以进行数据校验.
     *
     * @param request HttpServletRequest
     * @param entity  实体对象
     * @param errors  BindException 可以添加错误信息
     * @param mm      ModelAndView
     * @param id      .
     */
    protected void beforeUpdate(HttpServletRequest request, HttpServletResponse response, V entity, BindException errors, ModelMap mm, String id) {
    }

    /**
     * 保存实体(update)回调函数，在返回视图之前调用用。可以继续添加返回信息.
     *
     * @param request  http请求.
     * @param response http响应.
     * @param mm       ModelMap.
     * @param vo       VO对象.
     */
    protected void afterUpdate(HttpServletRequest request, HttpServletResponse response, ModelMap mm, V vo) {
    }


    /**
     * 删除实体(remove.do)回调函数，在执行保存之前调用用。可以进行数据校验.
     *
     * @param request  http请求.
     * @param response http响应.
     * @param object   实体对象
     */
    protected void beforeRemove(HttpServletRequest request, HttpServletResponse response, Object object) {
    }

    /**
     * 删除实体(remove.do)回调函数，在返回视图之前调用用。可以继续添加返回信息.
     *
     * @param request  http请求.
     * @param response http响应.
     * @param mm       ModelMap.
     * @param msg      删除成功后的信息.
     */
    protected void afterRemove(HttpServletRequest request, HttpServletResponse response, ModelMap mm, String msg) {
    }


    /**
     * 将视图层的vo 转换为 数据实体类.
     *
     * @param vo 视图层vo
     * @return 数据实体.
     */
    protected T voConvertEntity(V vo) {
        return null;
    }

    /**
     * 将数据库实体转换成视图层vo.
     *
     * @param entity 数据库实体.
     * @return 视图层vo.
     */
    protected V entityConvertVo(T entity) {
        return null;
    }

    /**
     * 将视图层的vo 转换为 数据实体类.
     *
     * @param vo 视图层vo
     * @return 数据实体.
     */
    protected List<T> voConvertEntityInList(List<V> vo) {
        return null;
    }

    /**
     * 将数据库实体转换成视图层vo.
     *
     * @param entity 数据库实体.
     * @return 视图层vo.
     */
    protected List<V> entityConvertVoInList(List<T> entity) {
        return null;
    }

}
